import java.util.*;

public class MauMau_Game {

	private static final int nPlayer = 4;
	
	private Random rand;
    private Vector<Integer> drawCards;  // Stapel aus dem Karten abgehoben werden
    private Vector<Integer> deckCards;  // Abgelegte Karten
    private int topCardCol; //Farbe der obersten Karte auf dem Stapel
    private int topCardMult; //Multiplikator: Wieviele 7er liegen drauf
    
    private MauMau_Intf player[];
    private MauMau_State state[];
    
    MauMau_Game(MauMau_Intf[] p) {
        player = p;
        state = new MauMau_State[4];
        deckCards = new Vector<Integer>();
        rand = new Random();
    };

    Integer drawCard() {
    	if(drawCards.size() == 0) {
    		while(deckCards.size() > 1) {
    			int n = deckCards.size()-2;
    			int i = (n == 0 ? 0 : rand.nextInt(n));
    			drawCards.add(deckCards.get(i));
    			deckCards.remove(i);
    		}
    	}
    	
    	if(drawCards.size() == 0)
    		return -1;
    	
    	int c = drawCards.get(0);
    	drawCards.remove(0);
    	return c;
    }
    
    Integer getTopCard() {
    	return deckCards.get(deckCards.size()-1);
    }
    
    private Vector<Integer> getActions(MauMau_State s) {
        Vector<Integer> v = new Vector<Integer>();
        for(int c = 0; c < s.getNrCards(); c++) {
        	int card = s.getCard(c);
        	int typ = s.getCardType(card);
        	int col = s.getCardColor(card);
	        if ( s.getCardType(getTopCard()) == MauMau_Constants.SIEBEN && topCardMult > 0) {
	        	if( typ == MauMau_Constants.SIEBEN )
	        		v.add(card);
	        } else if( typ == MauMau_Constants.BUBE ) {
	       		for(int t = 0; t<4; t++)
	       			v.add( MauMau_Constants.BUBE_BASE + t + col*4 );
	       	} else if ( typ == s.getCardType(getTopCard()) || col == topCardCol ) {
        		v.add(card);
        	} 
        }
        
        if ( s.getCardType(getTopCard()) == MauMau_Constants.SIEBEN && topCardMult > 0)
        	v.add(MauMau_Constants.TAKE_TWO);
        else
        	v.add(MauMau_Constants.TAKE_ONE);
        
        return v;
    }
    
    private MauMau_State performAction(MauMau_State s, Integer a) {

    	Vector<Integer> cs = s.getAllCards();
    	if ( a == MauMau_Constants.TAKE_ONE ) {
    		int c = drawCard();
    		if(c >= 0)
    			cs.add(c);
    	} else if ( a == MauMau_Constants.TAKE_TWO ) {
    		for(int t = 0; t < 2*topCardMult; t++) {
    			int c = drawCard();
    			if(c >= 0)
    				cs.add(c);
    		}
    		topCardMult = 0; 
    	} else if ( a <= 31 ) {
    		for(int i = 0; i < cs.size(); i++) {
    			if(cs.get(i) == a) {
    				if ( (a/4) == MauMau_Constants.SIEBEN && (getTopCard() / 4) == MauMau_Constants.SIEBEN)
    					topCardMult++;
    				
    				int c = cs.get(i);
    				deckCards.add(c);
    				topCardCol = c % 4;
    				cs.remove(i);
    				break;
    			}
    		}
    	} else if (a >= MauMau_Constants.BUBE_BASE && a <= MauMau_Constants.BUBE_END) {
    		int c = ((a / 4) % 4) + MauMau_Constants.BUBE * 4;
    		for(int i = 0; i < cs.size(); i++) {
    			if(cs.get(i) == c) {
    				deckCards.add(cs.get(i));
    				cs.remove(i);
    				topCardCol = a % 4;
    				break;
    			}    			
    		}    		
    	} else {
    		System.out.println("Ooops. Illegale Aktion");
    		System.out.println( 1 / 0);
    	}
    		
    	
    	MauMau_State result = new MauMau_State(cs);
    	return result;
    }

    public void play(int game) {
    	int current_player = game % nPlayer;
    	
        // Shuffle cards
        Vector<Integer> cardstmp = new Vector<Integer>();
        for(int t = 0; t < 32; t++)
        	cardstmp.add(t);
        drawCards = new Vector<Integer>();
        while(cardstmp.isEmpty() == false) {
        	int r = rand.nextInt(cardstmp.size());
        	drawCards.add(cardstmp.remove(r));   
        }
        //System.out.println("Shuffled cards (" + drawCards.size() + ") " + drawCards);
        
        // Start new game, pass 5 cards to each player
        topCardMult = 1;
        for(int t = 0; t < nPlayer; t++) {
        	int np = (t+current_player) % nPlayer;
        	player[np].newGame();
        	state[np] = new MauMau_State(drawCards.get(0), drawCards.get(1), drawCards.get(2), drawCards.get(3), drawCards.get(4));
        	drawCards.remove(0);
        	drawCards.remove(0);
        	drawCards.remove(0);
        	drawCards.remove(0);
        	drawCards.remove(0);
        }
        deckCards.add(drawCards.get(0));
        topCardCol = getTopCard() % 4;
        drawCards.remove(0);
        for(int t = 0; t < nPlayer; t++) {
        	state[t].setOpenCard(getTopCard(), topCardCol, topCardMult);
        	state[t].setNrCardsOponents(5,5,5);
        }
        
        while(true) {
        	
            state[current_player].setOpenCard(getTopCard(), topCardCol, topCardMult);
            state[current_player].setNrCardsOponents(state[(current_player+1)%4].getNrCards(), state[(current_player+2)%4].getNrCards(), state[(current_player+3)%4].getNrCards());
        	
        	//System.out.println("*******************************************************");
        	//System.out.println(" DrawCard: " + drawCards);
        	//System.out.println(" DeckCard: " + deckCards);
            //System.out.println("Player " + (current_player + 1) + " " + player[current_player].getName());
            //state[current_player].print();
            
            Vector<Integer> actions = getActions(state[current_player]);
            //System.out.println("  Moegliche Aktionen: " + actions);
            
            
            Integer a = player[current_player].step(new MauMau_State(state[current_player]), new Vector<Integer>(actions), 0.0, false);
            //System.out.println(" Aktion: " + a);
            state[current_player] = performAction(state[current_player], a);
            
            // System.out.println("  State nach Action:"); state[current_player].print();
            
            if(state[current_player].getNrCards() == 0)
            	break;
            
            // Acht?
            if(state[current_player].getCardType(a) == MauMau_Constants.ACHT)
            	current_player++;
            
            current_player = (current_player + 1) % nPlayer;
        }
        
        // Final call
        //System.out.println("##########################################################");
        int totalCards = 0;
        for(int i = 0; i < nPlayer; i++) 
        	totalCards += state[i].getNrCards();
        
        // Reward 
        // Player gewonnen -> + Anzahl der Karten von den anderen Mitspielern
        // Player verloren -> - Anzahl der eigenen Karten
        for(int i = 0; i < nPlayer; i++) 
        	if( state[i].getNrCards() == 0 )
        		player[i].step(new MauMau_State(state[i]), new Vector<Integer>(), totalCards, true);
        	else
        		player[i].step(new MauMau_State(state[i]), new Vector<Integer>(), -state[i].getNrCards(), true);
        		
        
    }
}
